/*
 * @Description:
 * @Author: Haor
 * @Date: 2022-04-01 16:50:23
 * @LastEditTime: 2022-04-06 22:15:41
 * @LastEditors: Haor
 */

/**
 * 类型检测
 * @param data 检测值
 * @reutn string/number/object...
 */
export const getType = (data): string => {
	return ({}).toString.call(data).slice(8, -1).toLowerCase()
}

/**
 * 是否为json
 * @param {any} data
 * @return {boolean}
 */
export const isJson = (data = null) => {
	try {
		if (typeof data !== 'string') return false
		const jsonObj = JSON.parse(data)
		return !!(jsonObj && ['array', 'object'].includes(getType(jsonObj)))
	} catch (error) {}
	return false
}

/**
 * 下划线转驼峰
 * @param {string} str
 * @return {string}
 */
export const lineToHump = (str: string): string => {
	return str.toLowerCase().replace(/([a-z])|-([a-z])/g, (s, s1) => {
		return s1.toUpperCase()
	})
}

/**
 * 驼峰转为下划线
 * @param {string} str
 * @return {string}
 */
export const humpToUnderline = (str: string): string => {
	return str.replace(/([A-Z])/g, '_$1').toLowerCase()
}

/**
 * 下滑线转为驼峰
 * @param {string} str
 * @return {string}
 */
export const underlineToCamelCase = (str: string): string => {
	return str.replace(/_(\w)/g, (all, letter) => {
		return letter.toUpperCase()
	})
}

/**
 * 中横线转为驼峰
 * @param {string} str
 * @return {string}
 */
export const middleLineToCamelCase = (str: string): string => {
	return str.replace(/-(\w)/g, (all, letter) => {
		return letter.toUpperCase()
	})
}

/**
 * 转换Key
 * @param obj
 * @param keyMap
 * @param isDeep Boolean 是否深度
 * @return Object/Array
 */
export const convertKey = (obj: object, keyMap: object, isDeep?: boolean): object => {
	if (!['array', 'object'].includes(getType(obj))) {
		throw new TypeError('The first argument should be either an object or an array！')
	}
	if ({}.toString.call(keyMap) !== 'object') {
		throw new TypeError('The parameter keyMap should be an object!')
	}
	const res = obj instanceof Array ? [] : {}
	if (obj instanceof Object) {
		for (const key in obj) {
			const newKey = Object.keys(keyMap).includes(key) ? keyMap[key] : key
			res[newKey] = obj[key]

			//是否为深度转换
			if (isDeep && obj[key] instanceof Object && Object.keys(obj[key]).length) {
				res[newKey] = convertKey(obj[key], keyMap, isDeep)
			}
		}
	}
	return res
}

/**
 * 对象key转为驼峰
 * @param {Object} data
 * @returns {Object}
 */
export const objectKeyCamelCase = (data: object): object => {
	return Object.keys(data).reduce((res, key) => {
		res[underlineToCamelCase(key)] = data[key]
		return res
	}, {})
}

/**
 * 列表key转为驼峰
 * @param {Array<object>} data
 */
export const listUnderlineKeyToHump = (data: Array<object>): Array<object> => {
	return data.map((row) => objectKeyCamelCase(row))
}

/**
 * 列表分组
 * @param {Array} list 列表
 * @param {Function} cb 回调函数，分组所使用字段
 * @return {Array}
 */
export const listGroupBy = (list: Array<any>, cb: Function) => {
	if (!Array.isArray(list)) return {}
	return list.reduce((wrap, cur, idx) => {
		const groupKey = cb ? cb(cur, idx) : null
		if (!groupKey) return wrap
		if (!wrap[groupKey]) {
			wrap[groupKey] = []
		}
		wrap[groupKey].push(cur)
		return wrap
	}, {})
}

/**
 * 分页容器
 * @param {Number} pageIndex
 * @param {Number} pageSize
 * @return {Object}
 */
export const pageWrap = (pageIndex: number | string, pageSize: number | string) => {
	return {
		take: Number(pageSize) || 10,
		skip: (Number(pageIndex) - 1 || 0) * Number(pageSize)
	}
}

/**
 * 是否为数字
 * @param {any} val
 * @return {boolean}
 */
export const isNumber = (val: any): Boolean => {
	if (val === '') return false
	return /^[0-9]*$/.test(val)
}

/**
 * 删除list某一项
 * @param {Array} list 源数据
 * @param {Number|Function} delIdx 下标||每次执行回调函数
 * @param {Boolean} isModifyTarget 是否改变原数组, 默认返回新数组
 * @return {Array}
 */
export const listDeleteBy = (list: Array<any>, delIdx: number | ((itm: any, idx: number) => boolean) = -1, isModifyTarget = false) => {
	if (!Array.isArray(list) || delIdx === -1) return list
	if (typeof delIdx === 'number') {
		// 是否改变原数组
		if (isModifyTarget) {
			list.splice(delIdx, 1)
			return list
		}
		return list.reduce((pre, item, idx) => {
			if (idx !== delIdx) {
				pre.push(item)
			}
			return pre
		}, [])
	} else if (typeof delIdx === 'function') {
		let deleteIndex = -1
		const newList = list.reduce((pre, cur, idx) => {
			const cbRes = delIdx(cur, idx)
			if (cbRes) {
				deleteIndex = idx
				return pre
			}
			pre.push(cur)
			return pre
		}, [])

		// 是否改变原数组
		if (!isModifyTarget) return newList
		deleteIndex > -1 && list.splice(deleteIndex, 1)
		return list
	}
	return list
}

/**
 * 列表转为tree
 * @param {Array} list 列表
 * @param {Number|String} parentId 父亲id，调用传入根id
 */
export const listToTree = (list, parentId) => {
	let res = []
	if (!Array.isArray(list)) return []
	for (let i = 0, len = list.length; i < len; i++) {
		const menu = list[i]
		if (menu.pid === parentId) {
			res.push(menu)
			const children = listToTree(list, menu.id) // 找出下一级
			menu.children = children.length ? children : null
		}
	}
	return res
}

/**
 * 列表转为树，高性能浅拷贝版本
 * @param {Array} data
 * @param rootId
 * @return {*[]}
 */
export const toTree = (data, rootId) => {
	if (!data) return []
	const list = data
	const keyMap = {}
	const res = []
	while (list.length > 0) {
		const item = list.shift()
		if (!keyMap[item.id]) {
			item.children = []
			keyMap[item.id] = item
		}
		// 判断当前是否为根
		if (item.pid === rootId) {
			res.push(keyMap[item.id])
		} else {
			const parent = keyMap[item.pid] // 找到父级
			if (parent) {
				parent.children = Array.isArray(parent.children) ? parent.children.concat(item) : [item]
			} else {
				list.push(item) // 如果没有找到上级，放在最后执行，等找到上级了再执行
			}
		}
	}
	return res
}
